package com.ocean;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

@SuppressWarnings({ "rawtypes", "unchecked" })
public class DelegateConsole implements InvocationHandler {
	private Object[] bs;

	private DelegateConsole(Object[] bs) {
		this.bs = bs;
	}

	/*
	 * public static Object bind(Object... abs) { List aslist = new ArrayList();
	 * List bslist = new ArrayList(); for(Object obj:abs){ if(obj instanceof
	 * Class) aslist.add(obj); else bslist.add(obj); }
	 * //System.out.println(as[0].getClass().getName());
	 * //System.out.println(bs[0].getClass().getName()); return
	 * Proxy.newProxyInstance(aslist.get(0).getClassLoader(), aslist.toArray(),
	 * new DelegateConsole(bslist.toArray())); }
	 */
	public static Object bind(Class[] as, Object... bs) {
		// System.out.println(as[0].getClass().getName());
		// System.out.println(bs[0].getClass().getName());
		return Proxy.newProxyInstance(as[0].getClassLoader(), as,
				new DelegateConsole(bs));
	}

	public static <I> I bind(Class<I> a, Object... bs) {
		return (I) bind(new Class[] { a }, bs);
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object result = null;
		Object mbeginObj = null, mimplObj = null, mendObj = null;
		Method mbegin = null, mimpl = null, mend = null;

		for (int j = 0; j < bs.length; j++) {
			Method[] bms = bs[j].getClass().getMethods();
			for (int i = 0; i < bms.length; i++) {
				boolean anflag = bms[i].isAnnotationPresent(Delegate.class);
				if (anflag) {
					Delegate dl = bms[i].getAnnotation(Delegate.class);
					Class dlifl = Class.forName(dl.interfaceName());
					// System.out.println("method.getName():"+method.getName());
					// System.out.println("method.getParameterTypes():"+method.getParameterTypes());
					// System.out.println("method.getReturnType():"+method.getReturnType());

					if (dlifl.isAssignableFrom(proxy.getClass())
							&& dl.methodName().equals(method.getName())
							&& Arrays.equals(method.getParameterTypes(),
									bms[i].getParameterTypes())
							&& method.getReturnType().equals(
									bms[i].getReturnType())) {
						DelegatePolicy dp = dl.policy();
						if (dp == DelegatePolicy.Begin) {
							mbeginObj = bs[j];
							mbegin = bms[i];
						} else if (dp == DelegatePolicy.Implements) {
							mimplObj = bs[j];
							mimpl = bms[i];
						} else if (dp == DelegatePolicy.End) {
							mendObj = bs[j];
							mend = bms[i];
						}
					}
				}
			}
		}

		if (mimpl != null) {
			if (mbegin != null)
				mbegin.invoke(mbeginObj, args);
			result = mimpl.invoke(mimplObj, args);
			if (mend != null)
				mend.invoke(mendObj, args);
		}
		return result;
	}

}